﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Data;
using System.Globalization;

namespace ETRobocon.RaceTraking.GameManagement
{
    public class WSIDNameItem : INotifyPropertyChanged
    {
        private int _id = -1;
        private string _name = "";

        public WSIDNameItem()
        {
        }

        public WSIDNameItem(int id)
            : this()
        {
            _id = id;
        }

        public WSIDNameItem(int id, string name)
            : this(id)
        {
            _name = name;
        }

        public int ID
        {
            get { return _id; }
            set {
                _id = value;
                OnPropertyChanged("ID");
            }
        }
        public string Name
        {
            get { return _name; }
            set {
                _name = value;
                OnPropertyChanged("Name");
            }
        }

        public override string ToString()
        {
            return _name.ToString();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }

    public class WSTeamEntry : WSIDNameItem
    {
        private int? _bib = null;
        private WSGame _parent = null;
        private int _teamId;

        public WSTeamEntry()
            : base()
        {
        }

        public WSTeamEntry(WSGame parent)
            : base()
        {
            _parent = parent;
        }

        public WSTeamEntry(WSGame parent, int id, int teamId, string name, int? bib)
            : base(id, name)
        {
            _parent = parent;
            _bib = bib;
            _teamId = teamId;
        }

        public int TeamID
        {
            get { return _teamId; }
            set
            {
                _teamId = value;
                OnPropertyChanged("TeamID");
            }
        }
        public int? Bib
        {
            get { return _bib; }
            set
            {
                _bib = value;
                OnPropertyChanged("Bib");
            }
        }

        public WSGame Parent
        {
            get { return _parent; }
            set
            {
                _parent = value;
                OnPropertyChanged("Parent");
            }
        }

        public override string ToString()
        {
            return _bib.ToString() + ":" + base.ToString();
        }
    }

    public class WSRunner : INotifyPropertyChanged
    {
        public enum CourseName
        {
            IN,
            OUT
        }

        public enum RunnerStatus
        {
            Ready,
            Running,
            Completed,
            Retired,
            Obstructed,
            Declined
        }

        private WSTeamEntry _team;
        private WSTurn _turn;
        private WSBonusResultList _results = new WSBonusResultList();
        private int _runTime;
        private int _runPoint;
        private RunnerStatus _status;
        private CourseName _course;

        private string _teamName;
        private int? _teamBib;

        public WSRunner()
        {
        }
        public WSRunner(WSTeamEntry team, WSTurn turn)
        {
            _team = team;
            _turn = turn;
            _status = RunnerStatus.Ready;
            _runTime = 1200;
        }

        public CourseName Course
        {
            get { return _course; }
            set {
                _course = value;
                OnPropertyChanged("Course");
            }
        }

        public string TeamName
        {
            get { return _teamName; }
            set
            {
                _teamName = value;
                OnPropertyChanged("TeamName");
            }
        }
        public int? TeamBib
        {
            get { return _teamBib; }
            set
            {
                _teamBib = value;
                OnPropertyChanged("TeamBib");
            }
        }

        public WSTeamEntry Team { get { return _team; }
            set
            {
                _team = value;
                TeamName = value.Name;
                TeamBib = value.Bib;
            }
        }
        
        public WSTurn Turn { get { return _turn; } set { _turn = value; } }
        public int RunTime {
            get { return _runTime; }
            set {
                _runTime = value;
                OnPropertyChanged("RunTime");
            }
        }
        public int RunPoint
        {
            get { return _runPoint; }
            set
            {
                _runPoint = value;
                OnPropertyChanged("RunPoint");
            }
        }

        public WSBonusResultList BonusResults { get { return _results; } }

        public bool IsReady { get { return (_status == RunnerStatus.Ready); } }
        public bool IsRunning { get { return (_status == RunnerStatus.Running); } }
        public bool IsCompleted { get { return (_status == RunnerStatus.Completed); } }
        public bool IsRetired { get { return (_status == RunnerStatus.Retired); } }
        public bool IsObstructed { get { return (_status == RunnerStatus.Obstructed); } }

        public RunnerStatus Status { 
            get { return _status; }
            set {
                _status = value;
                OnPropertyChanged("Status");
            }
        }
        public bool IsInCourse { get { return _team.Equals(_turn.InCourseEntry); } }
        public bool IsOutCourse { get { return _team.Equals(_turn.OutCourseEntry); } }

        public void UpdateBonusClearedStatus(string scName, bool cleared)
        {
            WSBonusResult result = GetBonusResult(scName);
            if (result != null)
            {
                result.Cleared = cleared;
            }
        }

        public WSBonusResult GetBonusResult(string scName)
        {
            foreach (WSBonusResult result in _results)
            {
                if (result.ShortCut.CompareTo(scName) == 0)
                {
                    return result;
                }
            }
            return null;
        }

        public bool? GetBonusResultStatus(string scName)
        {
            WSBonusResult result = GetBonusResult(scName);
            if (result != null)
            {
                return result.Cleared;
            }
            return null;
        }
        public int? GetBonusResultPointX(string scName)
        {
            WSBonusResult result = GetBonusResult(scName);
            if (result != null)
            {
                return result.X;
            }
            return null;
        }
        public int? GetBonusResultPointY(string scName)
        {
            WSBonusResult result = GetBonusResult(scName);
            if (result != null)
            {
                return result.Y;
            }
            return null;
        }

        public void SetupBonusResult()
        {
            WSBonusSpecList bsList = null;
            if (IsInCourse)
            {
                bsList = _turn.Parent.Parent.OutCourseBonusSpecs;
            }
            else
            {
                bsList = _turn.Parent.Parent.InCourseBonusSpecs;
            }
            foreach (WSBonusSpec bs in bsList)
            {
                _results.Add(new WSBonusResult(bs));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        public void ClearResults()
        {
            this.RunTime = 0;
            this.RunPoint = 0;
            this.Status = RunnerStatus.Ready;
            foreach (WSBonusResult br in this.BonusResults)
            {
                br.Cleared = false;
            }
        }
    }

    [ValueConversion(typeof(WSRunner.RunnerStatus),typeof(int))]
    public class RunnerStatusConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // Status -> Index
            return (int)((WSRunner.RunnerStatus)value);
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // Index -> Status
            return (WSRunner.RunnerStatus)((int)value);
        }

    }

    public class WSBonusSpec : WSIDNameItem
    {
        private WSGame _parent;
        private string _shortcut;
        private string _descrip;
        private int _point;

        public WSBonusSpec(WSGame parent)
            : base()
        {
            _parent = parent;
        }

        public WSBonusSpec(WSGame parent, int id, string name)
            : base(id, name)
        {
            _parent = parent;

        }
        public WSGame Parent
        {
            get { return _parent; }
            set { _parent = value; }
        }

        public string ShortCut
        {
            get { return _shortcut; }
            set { _shortcut = value; }
        }

        public string Descrip
        {
            get { return _descrip; }
            set { _descrip = value; }
        }

        public int Point
        {
            get { return _point; }
            set { _point = value; }
        }
    }

    public class WSBonusSpecList : ObservableCollection<WSBonusSpec>
    {
        public WSBonusSpecList()
            : base()
        {
        }
    }

    public class WSTurn : WSIDNameItem
    {
        private WSRound _parent;
        private WSTeamEntry _icREntry;
        private WSTeamEntry _ocREntry;

        private WSRunner _icRunner=null;
        private WSRunner _ocRunner=null;

        public WSTurn()
            : base()
        {
        }

        public WSTurn(WSRound parent)
            : base()
        {
            _parent = parent;
        }

        public WSTurn(WSRound parent, int id, int no)
            : base(id, no.ToString())
        {
            _parent = parent;
        }

        public WSTurn(WSRound parent,  int id, int no, WSTeamEntry icRE, WSTeamEntry ocRE)
            : this(parent,id, no)
        {
            _parent = parent;
            _icREntry = icRE;
            _ocREntry = ocRE;
        }
        public int? No
        {
            get
            {
                if (String.IsNullOrEmpty(Name))
                {
                    return null;
                }
                else
                {
                    return Int32.Parse(Name);
                }
            }
            set
            {
                if (value == null)
                {
                    Name = null;
                }
                else
                {
                    Name = value.ToString();
                }
                OnPropertyChanged("No");
            }
        }

        public WSTeamEntry InCourseEntry
        {
            get { return _icREntry; }
            set {
                _icREntry = value;
                OnPropertyChanged("InCourseEntry");
                OnPropertyChanged("InCourseRunner");
            }
        }

        public WSTeamEntry OutCourseEntry
        {
            get { return _ocREntry; }
            set {
                _ocREntry = value;
                OnPropertyChanged("OutCourseEntry");
                OnPropertyChanged("OutCourseRunner");
            }
        }

        public WSRunner InCourseRunner
        {
            get
            {
                if (_icRunner == null&&_icREntry!=null)
                {
                    _icRunner = new WSRunner(_icREntry, this);
                }
                return _icRunner;
            }
        }
        public WSRunner OutCourseRunner
        {
            get
            {
                if (_ocRunner == null&&_ocREntry!=null)
                {
                    _ocRunner = new WSRunner(_ocREntry, this);
                }
                return _ocRunner;
            }
        }

        public WSRound Parent { get { return _parent; } set { _parent = value; } }

        public override string ToString()
        {
            return "Turn[" + No.ToString() + "]";
        }
    }

    public class WSRound : WSIDNameItem
    {
        private WSGame _parent;

        public WSRound()
            : base()
        {
        }

        public WSRound(WSGame parent)
            : base()
        {
            _parent = parent;
        }
        public WSRound(WSGame parent, int id, int no)
            : base(id, no.ToString())
        {
            _parent = parent;
        }

        public int No
        {
            get
            {
                if (!string.IsNullOrEmpty(Name))
                {
                    return Int32.Parse(Name);
                }
                return -1;
            }
            set
            {
                Name = value.ToString();
                OnPropertyChanged("No");
            }
        }

        public WSGame Parent
        {
            get { return _parent; }
            set
            {
                _parent = value;
                OnPropertyChanged("Parent");
            }
        }

        public override string ToString()
        {
            return "Round[" + No.ToString() + "]";
        }
    }

    public class WSBonusResult : INotifyPropertyChanged
    {
        private WSBonusSpec _bonusSpec;
        private bool _cleared;
        private int _x;
        private int _y;

        public WSBonusResult(WSBonusSpec spec)
        {
            _bonusSpec = spec;
        }
        public string Name
        {
            get { return _bonusSpec.Name; }
        }
        public string ShortCut
        {
            get { return _bonusSpec.ShortCut; }
        }

        public int X
        {
            get { return _x; }
            set
            {
                _x = value;
                OnPropertyChanged("X");
            }
        }
        public int Y
        {
            get { return _y; }
            set
            {
                _y = value;
                OnPropertyChanged("Y");
            }
        }


        public WSBonusSpec Spec { get { return _bonusSpec; } }
        
        public bool Cleared { get { return _cleared; }
            set
            {
                _cleared = value;
                OnPropertyChanged("Cleared");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));

            }
        }
    }

    public class WSBonusResultList : ObservableCollection<WSBonusResult>
    {
        public WSBonusResultList()
            : base()
        {
        }
    }

    public class WSGame : WSIDNameItem
    {
        private WSRoundList _rounds = new WSRoundList();
        private WSTeamEntryList _teamEntries = new WSTeamEntryList();
        private WSBonusSpecList _icBonsuSpecs = new WSBonusSpecList();
        private WSBonusSpecList _ocBonusSpecs = new WSBonusSpecList();

        private WSContest _parent;
        private string _gameSpecId = "";

        public WSGame(WSContest parent)
            : base()
        {
            _parent = parent;
        }

        public WSGame(WSContest parent, int id, string name, string gameSpecId)
            : base(id, name)
        {
            _parent = parent;
            _gameSpecId = gameSpecId;
        }

        public WSContest Parent
        {
            get { return _parent; }
        }

        public string GameSpecId
        {
            get { return _gameSpecId; }
            set
            {
                _gameSpecId = value;
                OnPropertyChanged("GameSpecId");
            }
        }

        public WSRoundList Rounds { get { return _rounds; } }
        public WSTeamEntryList TeamEntries { get { return _teamEntries; } }
        public WSBonusSpecList InCourseBonusSpecs { get { return _icBonsuSpecs; } }
        public WSBonusSpecList OutCourseBonusSpecs { get { return _ocBonusSpecs; } }
    }

    public class WSContest : WSIDNameItem
    {
        private WSGameList _games = new WSGameList();

        public WSContest()
            : base()
        {
        }

        public WSContest(int id, string name)
            : base(id, name)
        {
        }

        public WSGameList Games { get { return _games; } }

    }

    public class WSContestList : ObservableCollection<WSContest>
    {
        public WSContestList()
            : base()
        {
        }
        public void UpdateContents()
        {
            var rm = new ETRoboConTrakingSystem.ETRoboConRM.ETRoboConRaceMgmtClient();
//            using (WSRaceMgmt.RaceMgmt rm = new WSRaceMgmt.RaceMgmt())
            {
       //         WSRaceMgmt.ContestInfo[] contestInfos;
                ETRoboConTrakingSystem.ETRoboConRM.ContestInfo[] contestInfos;
                if (rm.GetContestInfo(out contestInfos))
                {
                    foreach (var contestInfo in contestInfos)
                    {
                        WSContest contest = new WSContest(contestInfo.ContestId, contestInfo.Name);
//                        WSRaceMgmt.GameInfo[] gameInfos;
                        ETRoboConTrakingSystem.ETRoboConRM.GameInfo[] gameInfos;
                        if (rm.GetGameInfo(out gameInfos, contestInfo.ContestId))
                        {
                            foreach (var gameInfo in gameInfos)
                            {
                                WSGame game = new WSGame(contest, gameInfo.GameId, gameInfo.Name, gameInfo.GameSpecId.ToString());
                                WSRound round1 = new WSRound(game);
                                round1.No = 1;
                                game.Rounds.Add(round1);
                                WSRound round2 = new WSRound(game);
                                round2.No = 2;
                                game.Rounds.Add(round2);
                                SetupBonusSpecsOfGame(rm, game, ETRoboConTrakingSystem.ETRoboConRM.CourseName.IN, game.InCourseBonusSpecs);
                                SetupBonusSpecsOfGame(rm, game, ETRoboConTrakingSystem.ETRoboConRM.CourseName.OUT, game.OutCourseBonusSpecs);

                                contest.Games.Add(game);
                            }
                        }
                        Add(contest);
                    }
                }
            }
            rm.Close();
        }

        private void SetupBonusSpecsOfGame(ETRoboConTrakingSystem.ETRoboConRM.ETRoboConRaceMgmtClient rm, WSGame game, ETRoboConTrakingSystem.ETRoboConRM.CourseName course, WSBonusSpecList bsList)
        {
          //  WSRaceMgmt.BonusSpecInfo[] bsInfos;
            ETRoboConTrakingSystem.ETRoboConRM.BonusSpecInfo[] bsInfos;
            if (rm.GetBonusSpecInfo(out bsInfos, game.ID, course))
            {
                foreach (var bs in bsInfos)
                {
                    WSBonusSpec wbs = new WSBonusSpec(game, bs.BonusSpecId, bs.Name);
                    wbs.ShortCut = bs.ShortName;
                    wbs.Point = bs.Point;
                    bsList.Add(wbs);
                }
            }
        }
    }

    public class WSGameList : ObservableCollection<WSGame>
    {
        public WSGameList()
            : base()
        {
        }
    }

    public class WSRoundList : ObservableCollection<WSRound>
    {
        public WSRoundList()
            : base()
        {
        }
    }

    public class WSTeamEntryList : ObservableCollection<WSTeamEntry>
    {
        public WSTeamEntryList()
            : base()
        {
        }
    }


}

